import * as http from 'http';
import * as qs from 'querystring';
import * as URL from 'url';
import GetPort from 'get-port';
import sign from './sign';
import { logError } from './utils';

type THttpBody = {
  body: any;
  valid: boolean;
};

type THookData = {
  status: boolean;
} & ({ body: any } | { body?: any });

export function notFound(res: http.ServerResponse, message?: string): void {
  res.statusCode = 404;
  const body = ['404'];
  if (message) body.push(message);
  res.end(body.join(', '));
}

/**
 * 获取post请求的body
 */
export async function getHttpBody(req: http.IncomingMessage, secret = ''): Promise<THttpBody> {
  return new Promise((resolve, reject) => {
    let data = '';

    req.on('data', chunk => {
      data += chunk;
    });

    req.on('end', () => {
      try {
        const valid = sign(req, secret, data)
        const contentType = req.headers['content-type'];

        if (contentType === 'application/json') {
          resolve({ body: JSON.parse(data), valid });
        } else if (contentType === 'application/x-www-form-urlencoded') {
          let body = qs.parse(data);
          if (body.payload) {
            body = JSON.parse(typeof body.payload === 'string' ? body.payload : '');
          }
          resolve({ body, valid });
        } else {
          resolve({ body: data, valid });
        }
      } catch (err) {
        reject(err);
      }
    });

    req.on('error', (err) => {
      reject(err);
    });
  });
}

/**
 * 获取url中的参数
 */
export function getHttpQuery(req: http.IncomingMessage): any {
  const urlObj = URL.parse(req.url || '{}');
  const query: any = urlObj.query ? qs.parse(urlObj.query) : {};
  return query;
}

/**
 * 获取端口，如果未提供port参数则随机从8000-8100中选择
 */
export async function getPort(port?: number | string): Promise<number> {
  if (port !== undefined && /^\d+$/.test(String(port))) {
    const p = await GetPort({ port: Number(port) });
    if (p !== Number(port)) {
      await logError('', 'start', `${port} 端口已被占用`);
      process.exit(1);
    }
    return p;
  }
  return await GetPort({ port: GetPort.makeRange(8000, 8100) });
}

type TConditionHandler = (body: any) => boolean;
async function returnHookData(req: http.IncomingMessage, secret: string, conditionHandler: TConditionHandler): Promise<THookData> {
  const result = await getHttpBody(req, secret);
  if (result.valid && conditionHandler(result.body)) {
    return { status: true, body: result.body };
  }
  return { status: false };
}
/**
 * 判断是否是添加标签事件，并返回body
 */
export async function getHookData(req: http.IncomingMessage, secret = ''): Promise<THookData> {
  const reg1 = /^refs\/tags\/v(\d+\.)*\d+$/;
  const reg2 = /^v(\d+\.)*\d+$/;
  const giteeEvent = req.headers['x-gitee-event'];
  const githubEvent = req.headers['x-github-event'];
  const gitlabEvent = req.headers['x-gitlab-event'];

  if (giteeEvent) {
    if (giteeEvent === 'Tag Push Hook') {
      // created为true时为创建
      return await returnHookData(req, secret, (body) => body.created && reg1.test(body.ref));
    }
  } else if (githubEvent) {
    if (githubEvent === 'create') {
      // 创建分支和添加tag都是create事件； 删除tag是push事件；
      return await returnHookData(req, secret, (body) => body.ref_type === 'tag' && reg2.test(body.ref));
    }
  } else if (gitlabEvent) {
    if (gitlabEvent === 'Tag Push Hook') {
      // 添加和删除tag都是`Tag Push Hook`事件；添加tag时commits为非空数组；
      return await returnHookData(req, secret, (body) => body.commits.length > 0 && reg1.test(body.ref));
    }
  } else {
    for (const key in req.headers) {
      if (/^x-[\w-]+-event$/i.test(key)) {
        const eventName = req.headers[key];
        if (typeof eventName === 'string' && eventName === 'push') {
          return await returnHookData(req, secret, (body) => reg1.test(body.ref));
        }
      }
    }
  }

  return { status: false };
}